5种设计模式整理

一、单例模式

介绍:

单例对象的类只能有一个实例(只能new一个);
单例类必须给所有其他对象提供这一实例(全局访问静态方法);

作用:
解决一个全局使用的类频繁的创建与销毁;节省系统资源;

使用:
判断是否有这个实例,有则返回,没有则创建;直接用getInstance()调用。

public class SingleObject {
    private static SingleObject instance=new SingleObject();
    private SingleObject(){}

    public static SingleObject getInstance()
    {
        if (instance == null) {
            instance = new SingleObject();
        }
        return instance;
    }
}

应用实例:

统一调用发送短信接口;
统一调用打印机;
连接数据库操作;
追加日志;

二、工厂模式

介绍:
工厂模式让子类来决定创建的对象,达到封装目的。直接调用父类根据接收的参数决定创建哪一个类的对象实例。在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。

作用:
主要解决接口选择问题;

使用:
使用时不用负责创建对象,只需要传入工厂类参数,就会自动返回你需要的对象实例。ShapeFactory 类getShape()接口接受参数区分实例哪个对象

public class ShapeFactory {	
   //使用 getShape 方法获取形状类型的对象
   public Shape getShape(String shapeType){
      if(shapeType == null){
         return null;
      }		
      if(shapeType.equalsIgnoreCase("CIRCLE")){
         return new Circle();
      } else if(shapeType.equalsIgnoreCase("RECTANGLE")){
         return new Rectangle();
      }
      return null;
   }
}

使用该工厂,通过传递类型信息来获取实体类的对象。

public class FactoryPatternDemo {
   public static void main(String[] args) {
      ShapeFactory shapeFactory = new ShapeFactory();
      //获取 Circle 的对象,并调用它的 draw 方法
      Shape shape1 = shapeFactory.getShape("CIRCLE");
      //调用 Circle 的 draw 方法
      shape1.draw();

      //获取 Rectangle 的对象,并调用它的 draw 方法
      Shape shape2 = shapeFactory.getShape("RECTANGLE");
      //调用 Rectangle 的 draw 方法
      shape2.draw();

   }
}

应用实例:

一些接口类;

项目中多个数据库连接访问。

三、策略模式

介绍:
作用与工厂模式相类似,但是它属于行为型模式,可以在系统运行时动态改变。在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。策略对象改变 context 对象的执行算法。

 作用

自由切换相同父类的子类,避免多重条件(if else)判断

 使用:

  Strategy类是父类,申明了doOperation()方法,子类分别实现加法和减法功能,代码如下:

 OperationSubstract.java
public class OperationSubstract implements Strategy{
   @Override
   public int doOperation(int num1, int num2) {
      return num1 - num2;
   }
}
OperationMultiply.java

public class OperationMultiply implements Strategy{
   @Override
   public int doOperation(int num1, int num2) {
      return num1 * num2;
   }
}

context类(一个行为随着策略对象改变而改变的 context 对象) 

public class Context {
   private Strategy strategy;

   public Context(Strategy strategy){
      this.strategy = strategy;
   }

   public int executeStrategy(int num1, int num2){
      return strategy.doOperation(num1, num2);
   }
}

demo

public class StrategyPatternDemo {
   public static void main(String[] args) {
      Context context = new Context(new OperationAdd());		
      System.out.println("10 + 5 = " + context.executeStrategy(10, 5));

      context = new Context(new OperationSubstract());		
      System.out.println("10 - 5 = " + context.executeStrategy(10, 5));
   }
}

应用实例:
当一个系统中有许多类,它们之间的区别仅在于它们的行为,希望动态地让一个对象在许多行为中选择一种行为时;
当一个系统需要动态地在几种算法中选择一种时;
当一个对象有很多的行为,不想使用多重的条件选择语句来选择使用哪个行为时。

 

工厂模式和策略模式区别

工厂模式中我们仅仅须要传递对应的条件就能得到想要的一个对象(告诉别人我要干嘛、别人去做),然后通过这个对象实现算法的操作。只须要发出命令,由他人去实现
策略模式中使用时必须首先创建一个想使用的类对象(自己去做)。然后将该对象最为參数传递进去,通过该对象调用不同的算法。不只要发出命令,还得由自己亲自去做。

四、观察者模式

介绍:
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

作用:
在观察者模式中,发生改变的对象称为观察目标,而被通知的对象称为观察者,一个观察目标可以对应多个观察者,而且这些观察者之间可以没有任何相互联系,可以根据需要增加和删除观察者,使得系统更易于扩展。

使用:

 观察者模式使用三个类 Subject、Observer 和 Client。Subject 对象带有绑定观察者到 Client 对象和从 Client 对象解绑观察者的方法。我们创建 Subject类、Observer 抽象类和扩展了抽象类 Observer 的实体类。

import java.util.ArrayList;
import java.util.List;

public class Subject {	
   private List<Observer> observers 
      = new ArrayList<Observer>();
   private int state;
   public int getState() {
      return state;
   }
   public void setState(int state) {
      this.state = state;
      notifyAllObservers();
   }
   public void attach(Observer observer){
      observers.add(observer);		
   }
   public void notifyAllObservers(){
      for (Observer observer : observers) {
         observer.update();
      }
   } 	
}

Observer 类

public abstract class Observer {
   protected Subject subject;
   public abstract void update();
}

实体观察类,只写一个

public class BinaryObserver extends Observer{

   public BinaryObserver(Subject subject){
      this.subject = subject;
      this.subject.attach(this);
   }

   @Override
   public void update() {
      System.out.println( "Binary String: " 
      + Integer.toBinaryString( subject.getState() ) ); 
   }
}

使用 Subject 和实体观察者对象。

public class ObserverPatternDemo {
   public static void main(String[] args) {
      Subject subject = new Subject();

      new OctalObserver(subject);
      new BinaryObserver(subject);

      System.out.println("First state change: 15");	
      subject.setState(15);
      System.out.println("Second state change: 10");	
      subject.setState(10);
   }
}

应用实例:

当一个抽象模型有两个方面,其中一个方面的操作依赖于另一个方面的状态变化时;
如果在封盖一个对象的时候,需要同时连带改变其他的对象,而且不知道究竟应该有对少对象需要被连带改变;
当一个对象必须通知其他的对象,但是你又希望这个对象和其他被他通知的对象是松散耦合的。

五、适配器模式

介绍:
作为两个不兼容的接口之间的桥梁,结合了两个独立接口的功能。

作用:
将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

使用:

 MediaAdapter 适配器类

public class MediaAdapter implements MediaPlayer {

   AdvancedMediaPlayer advancedMusicPlayer;

   public MediaAdapter(String audioType){
      if(audioType.equalsIgnoreCase("vlc") ){
         advancedMusicPlayer = new VlcPlayer();			
      } else if (audioType.equalsIgnoreCase("mp4")){
         advancedMusicPlayer = new Mp4Player();
      }	
   }

   @Override
   public void play(String audioType, String fileName) {
      if(audioType.equalsIgnoreCase("vlc")){
         advancedMusicPlayer.playVlc(fileName);
      }else if(audioType.equalsIgnoreCase("mp4")){
         advancedMusicPlayer.playMp4(fileName);
      }
   }
}

AudioPlayer 使用适配器类 MediaAdapter 传递所需的音频类型,及自己的内置方法

public class AudioPlayer implements MediaPlayer {
   MediaAdapter mediaAdapter; 

   @Override
   public void play(String audioType, String fileName) {		

      //播放 mp3 音乐文件的内置支持
      if(audioType.equalsIgnoreCase("mp3")){
         System.out.println("Playing mp3 file. Name: "+ fileName);			
      } 
      //mediaAdapter 提供了播放其他文件格式的支持
      else if(audioType.equalsIgnoreCase("vlc") 
         || audioType.equalsIgnoreCase("mp4")){
         mediaAdapter = new MediaAdapter(audioType);
         mediaAdapter.play(audioType, fileName);
      }
      else{
         System.out.println("Invalid media. "+
            audioType + " format not supported");
      }
   }   
}

调用:

public class AdapterPatternDemo {
   public static void main(String[] args) {
      AudioPlayer audioPlayer = new AudioPlayer();

      audioPlayer.play("mp3", "beyond the horizon.mp3");
      audioPlayer.play("mp4", "alone.mp4");
      audioPlayer.play("vlc", "far far away.vlc");
      audioPlayer.play("avi", "mind me.avi");
   }
}

应用实例:
修改一个正常运行的系统的接口,这时应该考虑使用适配器模式。

 

参考详细的设计模式:http://www.php.cn/design-pattern/design-pattern-tutorial.html

 

posted @ 2018-12-24 17:48  Quentin-wy  阅读(1031)  评论(1编辑  收藏  举报